﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Diagnostics;
using System.Windows.Forms;
using Utils;

namespace EDMX_Modifier
{
    class Program
    {
        static List<string> UniqueIdentifierKeysToIdentityExclusions
        {
            get
            {
                var exclusions = new List<string>();

                // edits here

                exclusions.Add("User");

                return exclusions;
            }
        }

        static int Main(string[] args)
        {
            try
            {
                if (args.Length < 1 || args.Length > 3)
                {
                    ShowSyntax();
                    return 1;
                }

                bool _identity = false;

                var directoryInfo = new DirectoryInfo(args[0]);

                foreach (var fileInfo in directoryInfo.GetFiles("*.edmx"))
                {
                    string infilename = fileInfo.FullName;
                    string outfilename = string.Empty;
                    string temp = args.Length > 1 ? args[1] : infilename;

                    if (fileInfo.IsReadOnly)
                    {
                        fileInfo.MakeWritable();
                    }

                    if (temp.ToLower().Equals("/identity"))
                    {
                        outfilename = infilename;
                        _identity = true;
                    }
                    else
                    {
                        outfilename = temp;
                    }
                    if (args.Length == 3)
                        if (_identity == false)
                            _identity = args[2].ToLower().Equals("/identity");
                        else
                        {
                            ShowSyntax();
                            return 1;
                        }

                    XDocument x = XDocument.Parse(File.ReadAllText(infilename));

                    var nsmgr = new XmlNamespaceManager(new NameTable());
                    nsmgr.AddNamespace("ssdl", "http://schemas.microsoft.com/ado/2009/02/edm/ssdl");
                    nsmgr.AddNamespace("edm", "http://schemas.microsoft.com/ado/2008/09/edm");
                    nsmgr.AddNamespace("edmx", "http://schemas.microsoft.com/ado/2008/10/edmx");
                    XNamespace annotation = "http://schemas.microsoft.com/ado/2009/02/edm/annotation";

                    var copyfrom = x.XPathSelectElements("//edm:Property", nsmgr);
                    var tochange = x.XPathSelectElements("//ssdl:Property", nsmgr);

                    foreach (var t in copyfrom)
                    {
                        if (t.Attributes().Any(pr => pr.Name.LocalName == "StoreGeneratedPattern" && (pr.Value == "Computed" || (_identity && pr.Value == "Identity"))))
                        {
                            string name = t.Parent.Attribute("Name").Value;
                            string prop = t.Attribute("Name").Value;
                            string opertype = t.Attribute(annotation + "StoreGeneratedPattern").Value;
                            Console.WriteLine("Found Computed property {0}.{1} = {2}", name, prop, opertype);

                            var tc = tochange.Where(el => el.Parent.Attribute("Name").Value == name && el.Attribute("Name").Value == prop).Single();
                            string current = tc.Attribute("StoreGeneratedPattern") != null ? tc.Attribute("StoreGeneratedPattern").Value : null;
                            if (current == null)
                                tc.Add(new XAttribute("StoreGeneratedPattern", opertype));
                            else
                                Console.WriteLine(" Property already set to {0}. Not modifying this one to be {1}.", current, opertype);
                        }
                    }

                    // change uniqueidentifier keys to Identity

                    var enityTypes = x.XPathSelectElements("//ssdl:EntityType", nsmgr);

                    foreach (var t in enityTypes)
                    {
                        var entityName = t.Attribute("Name").Value;

                        if (!UniqueIdentifierKeysToIdentityExclusions.Contains(entityName))
                        {
                            var key = t.XPathSelectElement("./ssdl:Key/ssdl:PropertyRef", nsmgr);
                            var keyName = key.Attribute("Name").Value;
                            var prop = t.XPathSelectElement("./ssdl:Property[@Name='" + keyName + "' and @Type='uniqueidentifier']", nsmgr);

                            if (prop != null && prop.Attribute("StoreGeneratedPattern") == null)
                            {
                                prop.Add(new XAttribute("StoreGeneratedPattern", "Identity"));
                            }
                        }
                    }

                    x.Save(outfilename);
                }

                return 0;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Edmx Modifier - Error");

                Console.ForegroundColor = ConsoleColor.DarkRed;
                Console.WriteLine(ex.ToString());
                return 2;
            }
        }

        private static void ShowSyntax()
        {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("Syntax: EDMXModifier infile.edmx [outfile.edmx] [/identity]");
            Console.WriteLine(" Modifies an EDMX file, extending table properties marked as 'Computed' to be ignored when");
            Console.WriteLine(" EF4 writes entities to the database.");
            Console.WriteLine(" This allows the database to provide values via the 'Default Value or Binding' property.");
            Console.WriteLine(" If the /identity flag is specified then Identity columns are included in the transformation.");
        }
    }
}
